﻿using System;
using System.Text;
using System.IO;
using System.Net;
using System.Collections.Generic;

namespace MyMailWp8.Protocol
{
    internal class CMPopRecv : CMPopBase
    {
        private int _ReceiveState = 0;//0-init,1-get ok flag,2-receive mime data,
        //private int recvResult = 0;
        private int _mail2Get = 0;

        private String _stringRawDatabuf;
        private String _stringMimeDatabuf;
        List<string> _uidList;
        string _currentMailUid;

        private uint _newMailId = 0;

        public CMPopRecv(AsyncSocketClient sockClient)
            : base(sockClient)
        {
            ;
        }

        public bool getMail(List<string> uidList)
        {
            _uidList = uidList;
            _mail2Get = uidList.Count;
            if (_mail2Get <= 0)
            {
                DefaultLogger.Log.LogDebug("CMPopRecv:getMail " + "no more mails\r\n");
                return false;
            }

            _currentMailUid = uidList[0];
            uidList.RemoveAt(0);
            GetMailByUID(_currentMailUid);

            string dumpInfo = String.Format("CMPopRecv: mailcount = " + _mail2Get.ToString() + "\r\n");
            DefaultLogger.Log.LogDebug(dumpInfo);
            return true;
        }

        public uint GetNewMailId()
        {
            return _newMailId;
        }

        public void GetNextMail()
        {
            //get more mail
            _mail2Get = _uidList.Count;

            string dumpInfo = String.Format("CMPopRecv: mailcount = " + _mail2Get.ToString() + "\r\n");
            DefaultLogger.Log.LogDebug(dumpInfo);

            if (_mail2Get > 0)
            {
                _currentMailUid = _uidList[0];
                _uidList.RemoveAt(0);
                GetMailByUID(_currentMailUid);
            }
            else
            {
                _ReceiveState = 10;
                DefaultLogger.Log.LogDebug("GetNextMail");
                int nState = (int)(CMPopState.CMPOP_Quit);
                ChangeCMPopSmtpState(nState);
            }
        }

        override public int ParseData(String inString)
        {
            if (inString == null)
                return 0;

            if (_stringRawDatabuf == null)
                _stringRawDatabuf = String.Copy(inString);
            else
                _stringRawDatabuf += inString;

            //     DefaultLogger.Log.LogDebug("CMPopRecv: parse data\r\n");

            int nTrimpos = 0;
            switch (_ReceiveState)
            {
                //_ReceiveState:  0-init,1-got ok flag,2-receive mime data,3-get mail content
                case 0:
                    {
                        nTrimpos = _stringRawDatabuf.IndexOf("\r\n");
                        if (nTrimpos == -1)
                        {
                            ReceiveData();
                            DefaultLogger.Log.LogDebug("not find return");
                            return 0;
                        }

                        if (_stringRawDatabuf.ToUpper().StartsWith("+OK") == true)
                        {
                            _ReceiveState = 1;
                            nTrimpos += 2;//pass away "/r/n"
                            _stringRawDatabuf = _stringRawDatabuf.Substring(nTrimpos);

                            GetMimeData();
                        }
                        else if (_stringRawDatabuf.ToUpper().StartsWith("-ERR") == true)
                        {
                            //error
                            PostServerRetError((int)SockMessageType.ReceiveFail);
                            DefaultLogger.Log.LogDebug("CMPopRecv:ParseData case 0" + _stringRawDatabuf + "\r\n");
                        }
                        else
                        {
                            //error
                            DefaultLogger.Log.LogDebug("CMPopRecv:ParseData case 0" + _stringRawDatabuf + "\r\n");
                        }
                    }
                    break;

                case 1://1-got ok flag
                    {
                        GetMimeData();
                    }
                    break;

                case 2://get mime raw data
                    //
                    {
                        GetMailRawData();
                    }
                    break;

                case 3://get one mail and send ESTO commanf to server
                    {
                        nTrimpos = _stringRawDatabuf.IndexOf("\r\n");
                        if (nTrimpos == -1)
                        {
                            ReceiveData();
                            DefaultLogger.Log.LogDebug("not find return");
                            return 0;
                        }

                        if (_stringRawDatabuf.ToUpper().StartsWith("+OK") == true)
                        {
                            //get more mail
                            GetNextMail();
                        }
                        else if (_stringRawDatabuf.ToUpper().StartsWith("-ERR") == true)
                        {
                            //error
                            DefaultLogger.Log.LogDebug("CMPopRecv:ParseData case 3" + _stringRawDatabuf + "\r\n");
                        }
                        else
                        {
                            //error
                            DefaultLogger.Log.LogDebug("CMPopRecv:ParseData case 3" + _stringRawDatabuf + "\r\n");
                        }
                    }
                    break;

                default:
                    break;
            }

            return 0;
        }


        private bool GetMailByUID(string mailUid)
        {
            _stringMimeDatabuf = null;
            _stringRawDatabuf = null;
            _ReceiveState = 0;
            _newMailId = 0;
            SendData("ERET " + mailUid + " 0 html\r\n");
            return true;
        }

        private bool GetMimeData()
        {
            int nTrimpos = _stringRawDatabuf.IndexOf("\r\n\r\n");
            if (nTrimpos == -1)
            {
                ReceiveData();
                return false;
            }

            DefaultLogger.Log.LogDebug("got mime data\r\n");

            //at now,got the message header
            _stringMimeDatabuf = null;
            _stringMimeDatabuf = String.Copy(_stringRawDatabuf.Substring(0, nTrimpos));

            //passby "\r\n\r\n"
            nTrimpos += 4;

            //continue to receive the message data
            _stringRawDatabuf = _stringRawDatabuf.Substring(nTrimpos);
            _ReceiveState = 2;

            GetMailRawData();
            return true;
        }

        private bool GetMailRawData()
        {
            if (_stringRawDatabuf.EndsWith(".\r\n") != true)
            {
                ReceiveData();
                return false;
            }

            bool success = true; //处理mime解析错误
            //got the all raw data,finish receive one mail
            //analysis mail data 
            MimeParse mimeParse = new MimeParse();
            try
            {
                mimeParse.ParseMime(_stringMimeDatabuf, _stringRawDatabuf);
            }
            catch (Exception e)
            {
                DefaultLogger.Log.LogDebug("mime parse error:" + e.ToString());
                PostServerRetError((int)SockMessageType.DataError);
                success = false;
            }

            if (success)
            {
                //save mail data to DB
                _newMailId = SaveReceivedMail(_currentMailUid, mimeParse);

                int nState = (int)(CMPopState.CMPOP_RecvedOneMail);
                ChangeCMPopSmtpState(nState);
            }

            //release resource for previous mail data
            _stringMimeDatabuf = null;
            _stringRawDatabuf = null;

            //change state to send ESTO
            {
                _ReceiveState = 3;

                //set mail state in sever 
                SendData("ESTO " + _currentMailUid + " +R\r\n");
                //only for debug 
                //SendData("ESTO " + _currentMailUid + " -R\r\n");
            }

            return true;
        }

        private uint SaveReceivedMail(string emailUID, MimeParse mimeParse)
        {

            PeDataModel peDataModel = PEDBManager.Instance().peDataModel;
            Email newMail;

            try
            {
                PEUtility.convertMessagePartToEmail(emailUID, mimeParse.messageHeader, mimeParse.messagePart, out newMail);
                peDataModel.AddMail(ref newMail);
                if (mimeParse.messagePart.IsMultiPart == true)
                {
                    foreach (MessagePart msgPart in mimeParse.messagePart.MessageParts)
                    {
                        if (msgPart.IsAttachment == true)
                        {
                            //write att info to DB
                            Attachment mailAtt = new Attachment();
                            mailAtt.originalFilename = ConvertLongFilename(msgPart.FileName);
                            string fileExt = Path.GetExtension(mailAtt.originalFilename);
                            mailAtt.localFile = System.Guid.NewGuid().ToString() + fileExt;
                            mailAtt.mimeTime = newMail.mimeDate;
                            mailAtt.downloadSize = 0;
                            mailAtt.totalSize = Convert.ToInt32(msgPart.X_Attachment_Size);
                            mailAtt.contentId = msgPart.ContentId;//Convert.ToInt32(msgPart.ContentId);
                            mailAtt.emailId = newMail.emailId;
                            mailAtt.emailUid = newMail.mailUID;
                            mailAtt.accountId = newMail.accountId;

                            peDataModel.AddMailAttInfo(ref mailAtt);
                        }
                    }
                }
                return newMail.emailId;
            }
            catch (Exception ex)
            {
                DefaultLogger.Log.LogDebug("SaveReceivedMail to DB failed" + ex.ToString() + "\r\n");
            }

            return 0;
        }

        private string ConvertLongFilename(string filename)
        {
            if (string.IsNullOrEmpty(filename))
                return filename;
            int len = filename.Length;
            if (len <= 64)
                return filename;
            string fileExt = Path.GetExtension(filename);
            int extLen = 0;
            if (!string.IsNullOrEmpty(fileExt))
                extLen = fileExt.Length;
            if (extLen > 32) //扩展名不能太长了
                extLen = 32;

            int rightLen = extLen + 6;
            int start = len - rightLen;

            string right = filename.Substring(start, rightLen);
            int leftLen = 64 - rightLen - 3;   //3->"..."
            string left = filename.Substring(0, leftLen);
            string ret = left + "..." + right;
            return ret;
        }
    }
}
